# -*- coding: utf-8 -*-
"""

    taggable.signals
    ----------------

    Signals and signal-related stuff.

    :copyright: 2008 by Gustavo Picon
    :license: Apache License 2.0

"""

from django.db import models, transaction



def on_obj_delete(self):
    """ Removes all related tagged stats objects to a deleted tagged object.
    
    Called when a tagged object is delete()d

    This must be called manually from the user defined model, like::

        def delete():
            self.ob_obj_delete()
            super(MyModel, self).delete()

    Why not use delete signals? Because this method needs the related objects,
    and:
      
      - related objects are already gone in post_delete
      - while related objects are available in pre_delete, there is no
        guarantee that they will really removed, because the class can cancel
        the operation in .delete()

    """

    for field_name, tagged_model in self._taggable_on_delete:
        tagged_model.objects.extra(
          where=['%s=%s'% (
                 tagged_model._meta.get_field_by_name(field_name)[0].column,
                 self.pk)]
        ).delete()

    transaction.commit_unless_managed()

def handler_tagged_subclass(signal, sender, **named):
    """ Handler for the class_prepared signal.
    """
    from taggable.models import Tagged

    if not issubclass(sender, Tagged):
        # we only want Tagged subclasses
        return

    sender._taggable_stats = {}
    # we start caching the stats fields
    for stats_fields, stats_model in sender.taggable_stats:
        sender._taggable_stats[tuple(sorted(stats_fields))] = (
            stats_fields, stats_model)

    for fieldname in sender._meta.get_all_field_names():
        field = sender._meta.get_field_by_name(fieldname)[0]
        if field.get_internal_type() != 'ForeignKey':
            continue
        rel_model = field.rel.to
        try:
            rel_model._taggable_on_delete
        except AttributeError:
            rel_model._taggable_on_delete = []
        for stats_fields, stats_model in sender.taggable_stats:
            if field.name not in stats_fields:
                rel_model._taggable_on_delete.append(
                    (field.name, sender)
                )

        rel_model.on_obj_delete = on_obj_delete

models.signals.class_prepared.connect(handler_tagged_subclass)

#~
